package TagRate.bookmarklet.client;
/**
 *   TagRate
 *   @author Jean-Lou Dupont
 */

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FormHandler;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.web_bloks.http.client.JSONResponse;
import com.web_bloks.system.client.Logger;
import com.web_bloks.types.client.StateType;
import com.web_bloks.url.client.Helper;
import com.web_bloks.widget.client.RatingWidget;
import com.web_bloks.widget.client.RichTextToolbarWidget;
import com.web_bloks.widget.client.StatusWidget;
import com.google.gwt.gears.client.Factory;
import com.google.gwt.gears.client.localserver.LocalServer;
import com.google.gwt.gears.client.localserver.ManagedResourceStore;
import com.google.gwt.gears.client.localserver.ManagedResourceStoreCompleteHandler;
import com.google.gwt.gears.client.localserver.ManagedResourceStoreErrorHandler;
import com.google.gwt.gears.client.localserver.ManagedResourceStoreProgressHandler;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class main implements EntryPoint {
	
	final static String MANAGED_LOCAL_STORE = "TagRateManagedStore";
	final static String MANIFEST_URL = "TagRate.bookmarklet.main.nocache.manifest";
	
	Timer timer = null;
	final int DEFAULT_TIMEOUT = 5000;

	//Gears related
	final GearsEventHandler gh = new GearsEventHandler();
	ManagedResourceStore ms = null;
	LocalServer ls = null;
	
	//Keyboard related
	EscKeyHandler eh = new EscKeyHandler();
	
	// GUI related
	RootPanel rootPanel;
	
	HTML htmlUrl;
	TextBox textBoxTitle = null;
	VerticalPanel verticalPanel = null;
	final FormPanel formPanel = new FormPanel();
	RichTextArea richTextAreaNotes;
	final Button buttonSubmit = new Button();
	RatingWidget ratingWidget;
	
	Hidden hiddenUrl;
	Hidden hiddenTitle;
	Hidden hiddenRating;
	Hidden hiddenNotes;
	
	RichTextToolbarWidget toolbar;
	StatusWidget statusWidget;
	
	HTML htmlFooterMessage;
	
	HorizontalPanel horizontalPanel;
	
	public void onModuleLoad() {
		
		setupGears();
		
		rootPanel = RootPanel.get();
		rootPanel.setSize("100%", "100%");

		verticalPanel = new VerticalPanel();
		rootPanel.add(verticalPanel, 5, 5);
		verticalPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
		verticalPanel.setSize("100%", "100%");

		htmlUrl = new HTML();
		verticalPanel.add(htmlUrl);
		verticalPanel.setCellVerticalAlignment(htmlUrl, HasVerticalAlignment.ALIGN_TOP);
		verticalPanel.setCellHorizontalAlignment(htmlUrl, HasHorizontalAlignment.ALIGN_CENTER);

		textBoxTitle = new TextBox();
		verticalPanel.add(textBoxTitle);
		verticalPanel.setCellVerticalAlignment(textBoxTitle, HasVerticalAlignment.ALIGN_TOP);
		verticalPanel.setCellHorizontalAlignment(textBoxTitle, HasHorizontalAlignment.ALIGN_CENTER);
		textBoxTitle.setTabIndex(1);
		textBoxTitle.setVisibleLength(40);
		textBoxTitle.setWidth("100%");

		richTextAreaNotes = new RichTextArea();
		
		toolbar = new RichTextToolbarWidget( richTextAreaNotes );
		verticalPanel.add(toolbar);
		verticalPanel.setCellVerticalAlignment(toolbar, HasVerticalAlignment.ALIGN_BOTTOM);
		verticalPanel.setCellHorizontalAlignment(toolbar, HasHorizontalAlignment.ALIGN_CENTER);

		verticalPanel.add(richTextAreaNotes);
		verticalPanel.setCellVerticalAlignment(richTextAreaNotes, HasVerticalAlignment.ALIGN_TOP);
		verticalPanel.setCellHorizontalAlignment(richTextAreaNotes, HasHorizontalAlignment.ALIGN_CENTER);
		verticalPanel.setCellHeight(richTextAreaNotes, "200");
		verticalPanel.setCellWidth(richTextAreaNotes, "100%");
		richTextAreaNotes.setSize("100%", "200");
		richTextAreaNotes.setTabIndex(2);
		richTextAreaNotes.setText("");

		final HorizontalPanel horizontalPanel_1 = new HorizontalPanel();
		verticalPanel.add(horizontalPanel_1);
		verticalPanel.setCellVerticalAlignment(horizontalPanel_1, HasVerticalAlignment.ALIGN_TOP);
		verticalPanel.setCellHorizontalAlignment(horizontalPanel_1, HasHorizontalAlignment.ALIGN_CENTER);
		verticalPanel.setCellWidth(horizontalPanel_1, "100%");

		ratingWidget = new RatingWidget();
		horizontalPanel_1.add(ratingWidget);
		buttonSubmit.setFocus(true);
		horizontalPanel_1.add(buttonSubmit);
		buttonSubmit.setTabIndex(3);
		buttonSubmit.setText("submit");

		statusWidget = new StatusWidget();
		horizontalPanel_1.add(statusWidget);
		statusWidget.setVisible(false);

		htmlFooterMessage = new HTML();
		verticalPanel.add(htmlFooterMessage);
		htmlFooterMessage.setVisible(false);

		formPanel.setSize("1", "1");
		formPanel.setVisible(false);

		horizontalPanel = new HorizontalPanel();
		verticalPanel.add(horizontalPanel);
		horizontalPanel.setVisible(false);

		hiddenTitle = new Hidden();
		horizontalPanel.add(hiddenTitle);
		hiddenTitle.setVisible(false);
		hiddenTitle.setName("title");

		hiddenRating = new Hidden();
		horizontalPanel.add(hiddenRating);
		hiddenRating.setVisible(false);
		hiddenRating.setName("rating");

		hiddenNotes = new Hidden();
		horizontalPanel.add(hiddenNotes);
		hiddenNotes.setVisible(false);
		hiddenNotes.setName("notes");

		hiddenUrl = new Hidden();
		horizontalPanel.add(hiddenUrl);
		hiddenUrl.setVisible(false);
		hiddenUrl.setName("url");
		
		setup();
		
		processQuery( Helper.extractQueryFromLocation() );
	}

	private void processQuery(String q) {

		if (null== q)
			return;
		
		String t = Helper.extractComponent(q, "t");
		String u = Helper.extractComponent(q, "u");
		String s = Helper.extractComponent(q, "s");

		if (null!=t) {
			String td = Helper.decodeURIComponent( t );
			textBoxTitle.setText( td );
		}

		if (null!=u) {
			String ud = Helper.decodeURIComponent( u );
			hiddenUrl.setValue( ud );
			htmlUrl.setHTML("<a href='"+ud+"'>"+ud+"</a>");
		}
		
		if (null!=s) {
			richTextAreaNotes.setText( Helper.decodeURIComponent( s ) );			
		}
	}
	
	private void setup() {
		
		setupTimer();
		
		AppMessages am = GWT.create(AppMessages.class);
		
		buttonSubmit.setText(am.submit());
		formPanel.setAction("/api/tagrate/post/");
		verticalPanel.add(formPanel);
		formPanel.setMethod( FormPanel.METHOD_POST );

		buttonSubmit.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				//Logger.logInfo("buttonSubmit.onClick");
				statusWidget.setStatus(StateType.PENDING);				
				statusWidget.setVisible(true);				
				prepareFormForPosting();				
				formPanel.submit();
				timer.schedule(DEFAULT_TIMEOUT);
			}
		});

		
		formPanel.addFormHandler( new FormHandler() {

			public void onSubmit(FormSubmitEvent event) {
				Logger.logInfo(this.getClass()+".formHandler.onSubmit");
			}

			public void onSubmitComplete(FormSubmitCompleteEvent event) {
				Logger.logInfo(this.getClass()+".formHandler.onSubmitComplete, event msg=" + event.getResults());
				String response = event.getResults();
	
				timer.cancel();
				
				String code = extractCode(response);
				if ( "200" == code ) {
					statusWidget.setStatus(StateType.OK);
					closeApp();
					return;
				}
				
				// whatever other response, its bad
				String msg = extractMsg(response);				
				statusWidget.setStatus(StateType.ERROR);
				Logger.logWarn(this.getClass()+".onSubmitComplete, code["+code+"] msg["+msg+"]");
				
				if ( "401" == code ) {
					AppMessages am = GWT.create(AppMessages.class);
					htmlFooterMessage.setVisible(true);
					htmlFooterMessage.setHTML(am.login());
					return;
				}
				
				//TODO handle other error situations...
			}
			
		} );

		// Keyboard 'ESC' key
		richTextAreaNotes.addKeyboardListener( eh );
		buttonSubmit.addKeyboardListener( eh );
		
	}

	protected String extractCode(String response) {

		JSONResponse jr = JSONResponse.fromJSONString(response);
		
		if (null==jr)
			return null;
		
		if (!jr.contains("code"))
			return null;
		
		return jr.getString("code");
	}
	protected String extractMsg(String response) {

		JSONResponse jr = JSONResponse.fromJSONString(response);
		
		if (null==jr)
			return null;
		
		if (!jr.contains("msg"))
			return null;
		
		return jr.getString("msg");
	}
	
	protected boolean processResponse(String response) {
		
		JSONResponse jr = JSONResponse.fromJSONString(response);
		
		if (null==jr)
			return false;

		if (!jr.contains("code"))
			return false;
		
		return jr.getString("code") == "200";
	}
	
	/**
	 * Prepares the 'hidden' fields
	 * Title  => hiddenTitle
	 * Url    => hiddenUrl
	 * Notes  => hiddenNotes
	 * Rating => hiddenRating
	 * 
	 * Url component is set in processQuery.
	 */
	protected void prepareFormForPosting() {
		//Logger.logInfo(this.getClass()+".prepareFormForPosting BEGIN");
		hiddenRating.setValue( String.valueOf( ratingWidget.getRating() ) );
		hiddenNotes.setValue( richTextAreaNotes.getHTML() );
		hiddenTitle.setValue( textBoxTitle.getText() );
		//Logger.logInfo(this.getClass()+".prepareFormForPosting END");
	}
	
	protected void setupTimer() {
		
		if (null!=timer)
			return;
		
		timer = new Timer() {
			public void run() {
				statusWidget.setStatus(StateType.ERROR);
			}
		};
		
	}
	
	private void setupGears() {
		Factory f = Factory.getInstance();
		
		if (null==f) {
			Logger.logInfo(this.getClass()+".setupGears:  GEARS NOT available");			
			return;
		}
		
		Logger.logInfo(this.getClass()+".setupGears:  GEARS AVAILABLE");
		//try {
			ls = f.createLocalServer();
			
			ms = ls.createManagedStore( MANAGED_LOCAL_STORE );
			ms.setEnabled(true);
			ms.setManifestUrl( MANIFEST_URL );
		
			ms.setOnCompleteHandler( gh );
			ms.setOnErrorHandler( gh );
			//ms.setOnProgressHandler( gh );
		
			ms.checkForUpdate();
			
		//} catch(Exception e) {
		//	Logger.logWarn(this.getClass()+".setupGears:  EXCEPTION raised, msg=" + e.getMessage());
		//}
			
		Logger.logInfo(this.getClass()+".setupGears: init completed, currentVersion["+ms.getCurrentVersion()+"]");
	}
	
	final public class GearsEventHandler 
		implements ManagedResourceStoreCompleteHandler, ManagedResourceStoreErrorHandler, ManagedResourceStoreProgressHandler {

		public void onComplete(ManagedResourceStoreCompleteEvent event) {
			Logger.logInfo(this.getClass()+".onComplete, version=" + event.getNewVersion());	
		}

		public void onError(ManagedResourceStoreErrorEvent error) {
			Logger.logInfo(this.getClass()+".onError, msg=" + error.getMessage());
		}

		public void onProgress(ManagedResourceStoreProgressEvent event) {
			Logger.logInfo(this.getClass()+".onProgress, files completed="+event.getFilesComplete());
		}
		
	}

	/**
	 * TODO does not work...
	 */
	final public class EscKeyHandler 
		implements KeyboardListener {

		public void onKeyDown(Widget sender, char keyCode, int modifiers) {
			// TODO Auto-generated method stub	
		}

		public void onKeyPress(Widget sender, char keyCode, int modifiers) {
			
			Logger.logInfo(this.getClass()+".onKeyPress");
			
			if (keyCode == KeyboardListener.KEY_ESCAPE)
				closeApp();
		}

		public void onKeyUp(Widget sender, char keyCode, int modifiers) {
			// TODO Auto-generated method stub
			
		}	
	}
	
	public native void closeApp() /*-{
		$wnd.close();
	}-*/;
	
}//END
